Flash 5 - Part 8: Movie-Clips &emp; GUI gadgets

TAD

Introduction

This article focuses on how to use the basic building blocks (ie. Movie-Clips, Buttons and action-scripting) to construct some bigger, but still simple GUI gadgets.

I learnt most of these techniques the hard way using Flash 4 and simply switched to function based actions in Flash 5. For most traditional programmers Flash can be a shock (wave) because there is no real 'mainloop' or sub-routine calls in the familiar sense. Instead it's best to approach your project like an event driven task (even your 'mainloop'). The code and ideas presented in the following article are (perhaps) not the most elegant in terms of Object Orientated Design (hey, I'm a die-hard assembly freak ;) but they work!

Remember to use [CTRL-E] for Expert-Mode to enter the actions.

A-B-C The order of creation?

A few people have asked "In Flash, what order should I create stuff?" The answer is, "Any order you want!". You will find yourself having to switch backwards and forwards between components, Instances and the Library very often (usually when constructing stuff to get the Target paths correct and sometimes when debugging).

Tip: When constructing a small component inside a larger container (eg. a button inside a movie-clip) do this:

(1) Draw a simple box

(2) Insert --> Convert To Symbol to create your component

(3) Edit the component to add all the detail.

I found this much easier than creating a new, blank symbol, drawing it and then dragging an Instance of it into the larger container. (The Convert To Symbol cuts the shape into a Symbol and automatically places an Instance where the shape was!)

Top-Down, or, Bottom-Up ?

There is no clear order to construct your component hierarchy in. You can work either way, in fact Flash helps to support both in its Convert To Symbol and Break Apart options. Remember that you can easily cut and paste between symbols using the Copy/Cut Frames and the normal Cut/Paste/Paste-In-Place functions.

Convert To Symbol

This takes the currently selected items (which can be Instances and/or raw polygon shapes/text), constructs a NEW symbol, moves all the selected items INTO it and then drops an INSTANCE of that new symbol where the selected items originally were.

Note: If you have selected more than one layer then the Convert To Symbol option will 'flatten' your polygon shapes into a single layer. This means you might lose some transparency/layer effects because the overlapping shapes will be merged together. This is why I suggest drawing a simple (1 layer) shape, convert it and then edit it (adding layers effects etc...)

Break Apart

This option on the Modify menu has a dual purpose. One takes a selected text item and converts each font character into an editable polygon shape, so you can create some funky looking text if you wish. The second purpose takes a selected Instance and 'unwraps' it from the Symbol. Basically it's the reverse of Convert To Symbol. This is useful when you to pull a sub-component out of a large componet (eg. a Movie-clip from inside another Movie-Clip). It also breaks apart a symbol turning it back into the raw polygon shape, and yes, it can also mess up multiple-layer graphics :-(

Drop-down menu

Let's begin by creating a simple drop-down like menu. The basic technique can be reused for many other things like overlays, conditional buttons which appear/disappear depending on a certain state, Tool-tips and pop-up messages.

What we're aiming for is a button which when clicked brings up a menu, click it again and the menu disappears.

1) Place a Button Instance on the work-area

2) Select it and Convert To Symbol (Behavior: Movie-Clip, Name: 'Pop menu')

3) Using the Instance-panel, call it 'mcMenu'

4) Edit the Symbol (which is now a Button inside a Movie-Clip)

5) Insert KeyFrame (right-click Time-line menu)

You should have 2 KeyFrames on the Time-line, each frame has the Button Instance in it.

6) Draw a white box (or any other shape you want) on frame:2 under the Button.

7) Add a 'stop( )' action to frame:1

You can save and preview the Flash movie now (hit [CTRL-ENTER] ) and you will only see the button (the first frame of the movie-clip).

8) Go back to the 'Pop Menu' movie-clip and on frame:1 click on the Button Instance and add the following Object-Actions

// btw, these // lines are just comments!
// you don't need to type them in ;-)
//
// actions for frame:1 button instance
//
on (release) {
	gotoAndStop (2);
} 

9) Go to frame:2 and add the following Object-Actions

// actions for frame:2 button instance
//
on (release) {
	gotoAndStop (1);
} 

Test the movie. If all goes well you will be able to open and close the menu by clicking on the button. As you can see we're toggling between frame:1 and frame:2 of our 'Pop Menu' using the gotoAndStop() action. Hey, I never said Flash was going to be difficult ;-)

Drop-down menu 2

This time we'll create the same effect but using a different approach. This time we'll only use a single Instance of the button, but add some reusable functions (these are useful when creating big projects).

1) Place a Button Instance on your stage/scene or 'work-area'

2) Draw a white box (or other such shape)

3) Select the shape and Convert To Symbol (Behaviour: Movie-Clip, Name:'Popski Menu')

4) Open the Instance-Panel and give the newly converted Symbol the Instance Name:'mcPop'

5) Edit the symbol (double-click)

6) On the Time-line drag the KeyFrame:1 to frame:2 (so you've created a blank frame at position:1)

7) Add a stop ( ) action on frame:1

8) Click on the 'Scene' (or double-click on the white, faded background)

9) Add the following Frame-Actions to frame:1 on the main, scene Time-line.

// Frame-Actions on main Scene time-line frame:1 
// 
object.prototype.ToggleMenu = function(movieOBJ) {
	if (movieOBJ._currentframe != 1) {
		HideMenu(movieOBJ);
	} else {
		ShowMenu(movieOBJ);
	}
}

object.prototype.ShowMenu = function(movieOBJ) {
	movieOBJ.gotoAndStop(2);
}

object.prototype.HideMenu = function(movieOBJ) {
	movieOBJ.gotoAndStop(1);
} 

10) Add the following Object-Actions to the Button Instance.

// actions for button instance
on (release) {
	ToggleMenu(mcPop);
} 

The result is the same as the first example, except we're passing the movie-clip object to our functions. The ToggleMenu( ) function examines the _currentframe property of the movie so it can tell the 'state' of it (frame:1 = hidden, frame:2 = show menu).

Animated menus

The two previous examples had 2 static frames, but there is no reason why we can't use the rest of the time-line to perform some motion tweening animation. The supplied ZIP file has all 3 types of menus so I won't put the code here. We've already covered the techniques required to make animated menu (simply use another Movie-Clip container and apply some Motion tweening). The idea is simple, use for example 10 frames for the movement animation and use a gotoAndPlay(1) action to open the menu and a gotoAndPlay(10) action to play the closing animation.

Tick-boxes

This uses the 2-frame toggle technique to produce the 2 states of a tick-box (or check-box). Again we use a Movie-Clip as a container for the 2 different states (ie. frames). In each KeyFrame we place a Button Instance, again the Object-Actions toggle between frame:1 and frame:2, the only difference is that we overlay a 'x' or a tick to show the tick-box is 'on'.

MainLoop:

Unlike a normal programming language where you are responsible for drawing each and every item on the screen, in Flash you have very little control over what is displayed. You have to place each item down in Frames and KeyFrames rather than rendering them yourself when needed. This is why the different states of the menu are put in place BEFORE the movie is published.

Flash is limited to roughly ~200,000 operations per frame tick. If you want to perform some action over the course of any length of time, you need to split your action-scripting over more than one frame. This can seem crazy at first, but remember Flash wasn't really designed to be a programming environment, but an animation package with some 'simple' controls added on. The smallest 'MainLoop' possible is 2 frames. You can NOT loop on a single frame!

Simple Drag &emp; Drop

For GUI gadgets like scroll-bars you need to be able to pick up objects and drop them down. The basic building blocks are (again) a Button Instance and a Movie-Clip. There are two actions which will allow a Movie-Clip to be attached and un-attached to the mouse cursor.

1) Place a Button Instance on the Stage.

2) Add these actions to the button

on (press) {
    startDrag (this);
}
on (release) {
    stopDrag ();
}

2) Select the Button and Convert To Symbol (Behavior: Movie-Clip)

Easy huh?

Using Instances &emp; their names

As you already know Movie-Clip Instances can have their own, unique names which means they can be 'Target-ted' by using the path to them. If you have already tried to use 2 or more tick-boxes or other self-contained components then you might have found a problem. The idea of placing all the actions for a particular task inside one component (which can then be re-used by using multiple Instances of it) may seem like a good idea, and in most case it is. But how do you identify one tick-box from another tick-box? Remember the actions are identical.

The answer is simple, use the Instance name because is one of the few properties of each Instance which can be unique. The common action inside the 'component' (ie. Movie-Clip) can read its unique Instance name and process that as a parameter.

The following code Snippets (taken from the MENUS.FLA example Flash file) show how to read the Instance name and pass it to a common function. Normally this function would take the Instance name and use it to access some array to store the states of all the tick-boxes.

// proc: display the passed Instance name + flag
//
object.prototype.TickBoxClick = function(instname, flg) {
	_root.txtInfoBox = "Instance: "+instname+ " = "+flg;
}

These actions should be attached to the 2 Button Instances (frame:1 and frame:2)

// Object-action for frame:1 Button
 on (release) {
	TickBoxClick(this._name, true);
	gotoAndStop (2);
}

// Object-action for frame:2 Button
 on (release) {
	TickBoxClick(this._name, false);
	gotoAndStop (1);
}

States, Frames and Arrays

If you plan to revisit a user input form or to present some previously input data (such as passwords, tick-box states, preference settings etc..) then it's a very good idea to store their states in global variables such as an array, rather than relying on Text input fields or Movie-Clip frame states. One of the main reasons for doing this is that you can then access the data ANYWHERE including from within frames when those items aren't present.

// define a global array

_root.TickBoxStates = new Array(10);

Goto and Jumps

Another 'quirk' of the Flash action-scripting which might catch out programmers is that the gotoAndPlay( ) and gotoAndStop( ) actions do NOT happen immediately! Flash stores the frame number until ALL the actions for a particular frame have been processed and then jumps to the new frame number. (Yes, Flash processes all the actions BEFORE rendering the graphics -- this allows you to control the current frame's appearance using the goto actions).

// Example of the goto quirk

if (1==1) {
	gotoAndStop(2);
}

gotoAndStop(3);

The above code will always jump to frame 3. Remember, the goto actions control the frame numbers, NOT the action scriping location!!

Closing words

Phew, that was quite a long article, hope you kept up. If not, check out the supplied ZIP file for some examples.

Happy Scripting

TAD